"""K8s资源健康检查模块"""

from typing import Dict, Any, List
import logging
from dataclasses import dataclass
from enum import Enum
import os

logger = logging.getLogger(__name__)

class HealthStatus(Enum):
    """资源健康状态枚举"""
    HEALTHY = "healthy"
    WARNING = "warning"
    CRITICAL = "critical"
    UNKNOWN = "unknown"

@dataclass
class HealthCheckResult:
    """健康检查结果"""
    status: HealthStatus
    message: str
    details: Dict[str, Any]
    score: int  # 0-100的评分
    suggestions: List[str]  # 修复建议

class HealthChecker:
    def __init__(self, config: Dict[str, Any]):
        self.config = config
        self.health_check_config = config.get('health_check', {})
        self.level = self.health_check_config.get('level', 'basic')
        self.results: Dict[str, HealthCheckResult] = {}

    def check_resource(self, resource: Dict[str, Any]) -> HealthCheckResult:
        """检查单个资源的健康状态"""
        kind = resource.get('kind', '').lower()
        name = resource.get('metadata', {}).get('name', 'unknown')
        namespace = resource.get('metadata', {}).get('namespace', 'default')
        resource_id = f"{namespace}/{kind}/{name}"

        try:
            if kind == 'deployment':
                return self._check_deployment(resource)
            elif kind == 'statefulset':
                return self._check_statefulset(resource)
            elif kind == 'service':
                return self._check_service(resource)
            elif kind == 'pod':
                return self._check_pod(resource)
            elif kind == 'configmap':
                return self._check_configmap(resource)
            elif kind == 'secret':
                return self._check_secret(resource)
            elif kind == 'persistentvolumeclaim':
                return self._check_pvc(resource)
            elif kind == 'ingress':
                return self._check_ingress(resource)
            else:
                return HealthCheckResult(
                    status=HealthStatus.UNKNOWN,
                    message=f"Unsupported resource type: {kind}",
                    details={},
                    score=0,
                    suggestions=[]
                )
        except Exception as e:
            logger.error(f"Error checking health for {resource_id}: {str(e)}")
            return HealthCheckResult(
                status=HealthStatus.UNKNOWN,
                message=f"Error during health check: {str(e)}",
                details={'error': str(e)},
                score=0,
                suggestions=[]
            )

    def _check_deployment(self, resource: Dict[str, Any]) -> HealthCheckResult:
        """检查Deployment的健康状态"""
        status = resource.get('status', {})
        spec = resource.get('spec', {})
        metadata = resource.get('metadata', {})
        
        details = {}
        issues = []
        suggestions = []
        score = 100

        # 检查副本数
        desired_replicas = spec.get('replicas', 1)
        available_replicas = status.get('availableReplicas', 0)
        if available_replicas < desired_replicas:
            issues.append(f"Available replicas ({available_replicas}) less than desired ({desired_replicas})")
            suggestions.append("Check pod events and logs for issues")
            score -= 20

        # 检查更新策略
        strategy = spec.get('strategy', {})
        if not strategy.get('type'):
            issues.append("No update strategy specified")
            suggestions.append("Consider adding RollingUpdate strategy")
            score -= 10

        # 检查资源限制
        template = spec.get('template', {})
        containers = template.get('spec', {}).get('containers', [])
        for container in containers:
            resources = container.get('resources', {})
            if not resources.get('limits'):
                issues.append(f"Container {container.get('name')} has no resource limits")
                suggestions.append("Add resource limits to prevent resource exhaustion")
                score -= 15
            if not resources.get('requests'):
                issues.append(f"Container {container.get('name')} has no resource requests")
                suggestions.append("Add resource requests for better scheduling")
                score -= 10

        # 检查健康检查配置
        for container in containers:
            if not container.get('livenessProbe'):
                issues.append(f"Container {container.get('name')} has no liveness probe")
                suggestions.append("Add liveness probe to detect and restart unhealthy containers")
                score -= 15
            if not container.get('readinessProbe'):
                issues.append(f"Container {container.get('name')} has no readiness probe")
                suggestions.append("Add readiness probe to ensure proper traffic routing")
                score -= 15

        # 检查镜像标签
        for container in containers:
            image = container.get('image', '')
            if ':latest' in image:
                issues.append(f"Container {container.get('name')} uses latest tag")
                suggestions.append("Use specific version tags for better version control")
                score -= 10

        # 检查安全上下文
        security_context = template.get('spec', {}).get('securityContext', {})
        if not security_context.get('runAsNonRoot'):
            issues.append("Pod does not enforce non-root user")
            suggestions.append("Set runAsNonRoot to true in security context")
            score -= 10

        # 检查标签和注解
        if not metadata.get('labels'):
            issues.append("No labels specified")
            suggestions.append("Add appropriate labels for better resource management")
            score -= 5

        # 确定最终状态
        if not issues:
            status = HealthStatus.HEALTHY
            message = "Deployment is healthy"
        elif score >= 70:
            status = HealthStatus.WARNING
            message = "Deployment has some issues that need attention"
        else:
            status = HealthStatus.CRITICAL
            message = "Deployment has critical issues that need immediate attention"

        details = {
            'issues': issues,
            'available_replicas': available_replicas,
            'desired_replicas': desired_replicas,
            'containers': len(containers),
            'has_resource_limits': all('limits' in c.get('resources', {}) for c in containers),
            'has_probes': all('livenessProbe' in c and 'readinessProbe' in c for c in containers)
        }

        return HealthCheckResult(
            status=status,
            message=message,
            details=details,
            score=score,
            suggestions=suggestions
        )

    def _check_statefulset(self, resource: Dict[str, Any]) -> HealthCheckResult:
        """检查StatefulSet的健康状态"""
        status = resource.get('status', {})
        spec = resource.get('spec', {})
        
        details = {}
        issues = []
        suggestions = []
        score = 100

        # 检查副本数
        desired_replicas = spec.get('replicas', 1)
        current_replicas = status.get('currentReplicas', 0)
        if current_replicas < desired_replicas:
            issues.append(f"Current replicas ({current_replicas}) less than desired ({desired_replicas})")
            suggestions.append("Check pod events and logs for issues")
            score -= 20

        # 检查更新策略
        update_strategy = spec.get('updateStrategy', {})
        if not update_strategy.get('type'):
            issues.append("No update strategy specified")
            suggestions.append("Consider adding RollingUpdate strategy")
            score -= 10

        # 检查持久化存储
        volume_claim_templates = spec.get('volumeClaimTemplates', [])
        if not volume_claim_templates:
            issues.append("No volume claim templates specified")
            suggestions.append("Add volume claim templates if persistent storage is needed")
            score -= 15

        # 检查服务名称
        service_name = spec.get('serviceName')
        if not service_name:
            issues.append("No service name specified")
            suggestions.append("Add service name for proper headless service configuration")
            score -= 15

        # 确定最终状态
        if not issues:
            status = HealthStatus.HEALTHY
            message = "StatefulSet is healthy"
        elif score >= 70:
            status = HealthStatus.WARNING
            message = "StatefulSet has some issues that need attention"
        else:
            status = HealthStatus.CRITICAL
            message = "StatefulSet has critical issues that need immediate attention"

        details = {
            'issues': issues,
            'current_replicas': current_replicas,
            'desired_replicas': desired_replicas,
            'has_volume_claims': bool(volume_claim_templates),
            'has_service_name': bool(service_name)
        }

        return HealthCheckResult(
            status=status,
            message=message,
            details=details,
            score=score,
            suggestions=suggestions
        )

    def _check_service(self, resource: Dict[str, Any]) -> HealthCheckResult:
        """检查Service的健康状态"""
        spec = resource.get('spec', {})
        
        details = {}
        issues = []
        suggestions = []
        score = 100

        # 检查选择器
        selector = spec.get('selector', {})
        if not selector:
            issues.append("No selector specified")
            suggestions.append("Add selector to target specific pods")
            score -= 20

        # 检查端口配置
        ports = spec.get('ports', [])
        if not ports:
            issues.append("No ports specified")
            suggestions.append("Add port configurations")
            score -= 20

        # 检查服务类型
        service_type = spec.get('type', 'ClusterIP')
        if service_type == 'LoadBalancer':
            if not spec.get('externalTrafficPolicy'):
                issues.append("No external traffic policy specified for LoadBalancer")
                suggestions.append("Set externalTrafficPolicy to Local or Cluster")
                score -= 10

        # 确定最终状态
        if not issues:
            status = HealthStatus.HEALTHY
            message = "Service is healthy"
        elif score >= 70:
            status = HealthStatus.WARNING
            message = "Service has some issues that need attention"
        else:
            status = HealthStatus.CRITICAL
            message = "Service has critical issues that need immediate attention"

        details = {
            'issues': issues,
            'type': service_type,
            'ports': len(ports),
            'has_selector': bool(selector)
        }

        return HealthCheckResult(
            status=status,
            message=message,
            details=details,
            score=score,
            suggestions=suggestions
        )

    def _check_pod(self, resource: Dict[str, Any]) -> HealthCheckResult:
        """检查Pod的健康状态"""
        status = resource.get('status', {})
        spec = resource.get('spec', {})
        
        details = {}
        issues = []
        suggestions = []
        score = 100

        # 检查Pod状态
        phase = status.get('phase', 'Unknown')
        if phase not in ['Running', 'Succeeded']:
            issues.append(f"Pod is in {phase} phase")
            suggestions.append("Check pod events and logs for issues")
            score -= 30

        # 检查容器状态
        container_statuses = status.get('containerStatuses', [])
        for container_status in container_statuses:
            if not container_status.get('ready', False):
                issues.append(f"Container {container_status.get('name')} is not ready")
                suggestions.append("Check container logs and events")
                score -= 20

        # 检查资源限制
        containers = spec.get('containers', [])
        for container in containers:
            resources = container.get('resources', {})
            if not resources.get('limits'):
                issues.append(f"Container {container.get('name')} has no resource limits")
                suggestions.append("Add resource limits to prevent resource exhaustion")
                score -= 15

        # 确定最终状态
        if not issues:
            status = HealthStatus.HEALTHY
            message = "Pod is healthy"
        elif score >= 70:
            status = HealthStatus.WARNING
            message = "Pod has some issues that need attention"
        else:
            status = HealthStatus.CRITICAL
            message = "Pod has critical issues that need immediate attention"

        details = {
            'issues': issues,
            'phase': phase,
            'containers': len(containers),
            'ready_containers': sum(1 for cs in container_statuses if cs.get('ready', False))
        }

        return HealthCheckResult(
            status=status,
            message=message,
            details=details,
            score=score,
            suggestions=suggestions
        )

    def _check_configmap(self, resource: Dict[str, Any]) -> HealthCheckResult:
        """检查ConfigMap的健康状态"""
        data = resource.get('data', {})
        binary_data = resource.get('binaryData', {})
        
        details = {}
        issues = []
        suggestions = []
        score = 100

        # 检查数据
        if not data and not binary_data:
            issues.append("No data specified")
            suggestions.append("Add configuration data")
            score -= 30

        # 检查数据大小
        total_size = len(str(data)) + len(str(binary_data))
        if total_size > 1024 * 1024:  # 1MB
            issues.append("ConfigMap data size exceeds 1MB")
            suggestions.append("Consider splitting into multiple ConfigMaps")
            score -= 20

        # 确定最终状态
        if not issues:
            status = HealthStatus.HEALTHY
            message = "ConfigMap is healthy"
        elif score >= 70:
            status = HealthStatus.WARNING
            message = "ConfigMap has some issues that need attention"
        else:
            status = HealthStatus.CRITICAL
            message = "ConfigMap has critical issues that need immediate attention"

        details = {
            'issues': issues,
            'data_keys': len(data),
            'binary_data_keys': len(binary_data),
            'total_size': total_size
        }

        return HealthCheckResult(
            status=status,
            message=message,
            details=details,
            score=score,
            suggestions=suggestions
        )

    def _check_secret(self, resource: Dict[str, Any]) -> HealthCheckResult:
        """检查Secret的健康状态"""
        data = resource.get('data', {})
        string_data = resource.get('stringData', {})
        
        details = {}
        issues = []
        suggestions = []
        score = 100

        # 检查数据
        if not data and not string_data:
            issues.append("No data specified")
            suggestions.append("Add secret data")
            score -= 30

        # 检查类型
        secret_type = resource.get('type', 'Opaque')
        if secret_type == 'Opaque' and not data and not string_data:
            issues.append("Opaque secret has no data")
            suggestions.append("Add secret data or use appropriate secret type")
            score -= 20

        # 确定最终状态
        if not issues:
            status = HealthStatus.HEALTHY
            message = "Secret is healthy"
        elif score >= 70:
            status = HealthStatus.WARNING
            message = "Secret has some issues that need attention"
        else:
            status = HealthStatus.CRITICAL
            message = "Secret has critical issues that need immediate attention"

        details = {
            'issues': issues,
            'type': secret_type,
            'data_keys': len(data),
            'string_data_keys': len(string_data)
        }

        return HealthCheckResult(
            status=status,
            message=message,
            details=details,
            score=score,
            suggestions=suggestions
        )

    def _check_pvc(self, resource: Dict[str, Any]) -> HealthCheckResult:
        """检查PersistentVolumeClaim的健康状态"""
        status = resource.get('status', {})
        spec = resource.get('spec', {})
        
        details = {}
        issues = []
        suggestions = []
        score = 100

        # 检查存储类
        storage_class = spec.get('storageClassName')
        if not storage_class:
            issues.append("No storage class specified")
            suggestions.append("Specify a storage class for better volume management")
            score -= 20

        # 检查访问模式
        access_modes = spec.get('accessModes', [])
        if not access_modes:
            issues.append("No access modes specified")
            suggestions.append("Specify access modes (e.g., ReadWriteOnce)")
            score -= 20

        # 检查容量
        resources = spec.get('resources', {})
        requests = resources.get('requests', {})
        if not requests.get('storage'):
            issues.append("No storage request specified")
            suggestions.append("Specify storage request size")
            score -= 20

        # 检查状态
        phase = status.get('phase', 'Unknown')
        if phase != 'Bound':
            issues.append(f"PVC is in {phase} phase")
            suggestions.append("Check if there are available PVs matching the requirements")
            score -= 30

        # 确定最终状态
        if not issues:
            status = HealthStatus.HEALTHY
            message = "PVC is healthy"
        elif score >= 70:
            status = HealthStatus.WARNING
            message = "PVC has some issues that need attention"
        else:
            status = HealthStatus.CRITICAL
            message = "PVC has critical issues that need immediate attention"

        details = {
            'issues': issues,
            'phase': phase,
            'storage_class': storage_class,
            'access_modes': access_modes,
            'has_storage_request': bool(requests.get('storage'))
        }

        return HealthCheckResult(
            status=status,
            message=message,
            details=details,
            score=score,
            suggestions=suggestions
        )

    def _check_ingress(self, resource: Dict[str, Any]) -> HealthCheckResult:
        """检查Ingress的健康状态"""
        spec = resource.get('spec', {})
        
        details = {}
        issues = []
        suggestions = []
        score = 100

        # 检查规则
        rules = spec.get('rules', [])
        if not rules:
            issues.append("No ingress rules specified")
            suggestions.append("Add ingress rules to define routing")
            score -= 30

        # 检查TLS配置
        tls = spec.get('tls', [])
        if not tls:
            issues.append("No TLS configuration specified")
            suggestions.append("Add TLS configuration for secure connections")
            score -= 20

        # 检查注解
        annotations = resource.get('metadata', {}).get('annotations', {})
        if not annotations.get('kubernetes.io/ingress.class'):
            issues.append("No ingress class specified")
            suggestions.append("Specify ingress class in annotations")
            score -= 15

        # 确定最终状态
        if not issues:
            status = HealthStatus.HEALTHY
            message = "Ingress is healthy"
        elif score >= 70:
            status = HealthStatus.WARNING
            message = "Ingress has some issues that need attention"
        else:
            status = HealthStatus.CRITICAL
            message = "Ingress has critical issues that need immediate attention"

        details = {
            'issues': issues,
            'rules': len(rules),
            'has_tls': bool(tls),
            'has_ingress_class': bool(annotations.get('kubernetes.io/ingress.class'))
        }

        return HealthCheckResult(
            status=status,
            message=message,
            details=details,
            score=score,
            suggestions=suggestions
        )

    def export_health_report(self, output_path: str, format_type: str = 'yaml') -> None:
        """导出健康检查报告
        
        Args:
            output_path: 输出文件路径
            format_type: 输出格式类型，支持：yaml, json, html, pdf, md
        """
        try:
            report = {
                'summary': {
                    'total_resources': len(self.results),
                    'healthy': sum(1 for r in self.results.values() if r.status == HealthStatus.HEALTHY),
                    'warning': sum(1 for r in self.results.values() if r.status == HealthStatus.WARNING),
                    'critical': sum(1 for r in self.results.values() if r.status == HealthStatus.CRITICAL),
                    'unknown': sum(1 for r in self.results.values() if r.status == HealthStatus.UNKNOWN),
                    'average_score': sum(r.score for r in self.results.values()) / len(self.results) if self.results else 0
                },
                'details': {
                    resource_id: {
                        'status': result.status.value,
                        'message': result.message,
                        'score': result.score,
                        'issues': result.details.get('issues', []),
                        'suggestions': result.suggestions
                    }
                    for resource_id, result in self.results.items()
                }
            }

            # 创建格式化器链
            template_dir = os.path.join(os.path.dirname(__file__), '..', 'templates')
            formatter = ReportFormatterFactory.create_formatter_chain(template_dir)
            
            # 处理格式化请求
            if not formatter.handle(report, format_type, output_path):
                raise ValueError(f"Unsupported format type: {format_type}")
            
            logger.info(f"Health report exported to {output_path} in {format_type} format")
        except Exception as e:
            logger.error(f"Error exporting health report: {str(e)}")
            raise 